package controllers

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"io"

	"strconv"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/httplib"
)

var (
	host      string
	secretId  string
	secretKey string
	taskChan  chan *filePutTask
)

type filePutTask struct {
	data  []byte
	uri   string
	retry int
}

func uploadTask() {

	for {

		task := <-taskChan

		beego.Debug("left task :", len(taskChan))
		_, err := PutObject(task.uri, task.data)
		if err != nil {
			beego.Error("file upload failed!", err, task.uri)
		}
	}
}

func addToUploadTask(uri string, data []byte) {
	task := filePutTask{
		uri:   uri,
		data:  data,
		retry: 1,
	}
	taskChan <- &task
}

func sha1_str(s string) string {
	h := sha1.New()
	io.WriteString(h, s)
	r := h.Sum(nil)
	return hex.EncodeToString(r[:])
}

func hmac_sha1_str(str1, str2 string) string {
	mac := hmac.New(sha1.New, []byte(str1))
	mac.Write([]byte(str2))
	r := mac.Sum(nil)
	return hex.EncodeToString(r[:])
}

func getAuthorization(uri string) string {
	/*
		Authorization:
		q-sign-algorithm=sha1&
		q-ak=AKIDQjz3ltompVjBni5LitkWHFlFpwkn9U5q&
		q-sign-time=1417773892;1417853898&
		q-key-time=1417773892;1417853898&
		q-header-list=host;x-cos-content-sha1;x-cos-storage-class&
		q-url-param-list=&
		q-signature=84f5be2187452d2fe276dbdca932143ef8161145
	*/
	q_sign_algorithm := "sha1"
	q_ak := secretId
	startStamp := time.Now().Unix()
	endStamp := startStamp + 30
	q_sign_time := strconv.FormatInt(startStamp, 10) + ";" + strconv.FormatInt(endStamp, 10)
	q_key_time := q_sign_time
	q_header_list := "host"
	q_url_param_list := ""

	/*
	   SignKey = HMAC-SHA1(SecretKey,"[q-key-time]")
	   HttpString = [HttpMethod]\n[HttpURI]\n[HttpParameters]\n[HttpHeaders]\n
	   StringToSign = [q-sign-algorithm]\n[q-sign-time]\nSHA1-HASH(HttpString)\n
	   Signature = HMAC-SHA1(SignKey,StringToSign)
	*/
	SignKey := hmac_sha1_str(secretKey, q_key_time)
	HttpString := "put\n" + uri + "\n\n" + "host=" + host + "\n"
	StringToSign := q_sign_algorithm + "\n" + q_sign_time + "\n" + sha1_str(HttpString) + "\n"
	beego.Debug(StringToSign)
	Signature := hmac_sha1_str(SignKey, StringToSign)

	Authorization := fmt.Sprintf("q-sign-algorithm=%s&q-ak=%s&q-sign-time=%s&q-key-time=%s&q-header-list=%s&q-url-param-list=%s&q-signature=%s",
		q_sign_algorithm, q_ak, q_sign_time, q_key_time, q_header_list, q_url_param_list, Signature)

	return Authorization
}

func CosClientInit(bucket, region, appid, SecretId, SecretKey string) {

	secretId = SecretId
	secretKey = SecretKey

	host = bucket + "-" + appid + ".cos." + region + ".myqcloud.com"

	taskChan = make(chan *filePutTask, 2000)
}

func PutObject(url string, data []byte) ([]byte, error) {

	fullUrl := "http://" + host + url
	authorization := getAuthorization(url)

	req := httplib.Put(fullUrl).SetTimeout(30*time.Second, 30*time.Second)

	req.Header("Content-Length", strconv.FormatInt(int64(len(data)), 10))
	req.Header("Authorization", authorization)
	req.Header("Connection", "close")

	return req.Body(data).Bytes()

}
